﻿using System.Reflection;

namespace ECommon
{
    /// <summary>
    /// 反射工具
    /// </summary>
    public static class ReflectionTool
    {
        /// <summary>
        /// 反射对象的属性锁
        /// </summary>
        private static readonly string _reflectLock = "reflectLock";

        /// <summary>
        /// 反射对象的属性集合锁
        /// </summary>
        private static readonly string _reflectPropertiesLock = "reflectPropertiesLock";

        /// <summary>
        /// 反射对象的属性缓存
        /// </summary>
        private static Dictionary<string, PropertyInfo> _propertyCache = new Dictionary<string, PropertyInfo>();

        /// <summary>
        /// 反射对象的属性集合缓存
        /// </summary>
        private static Dictionary<string, List<PropertyInfo>> _propertiesCache = new Dictionary<string, List<PropertyInfo>>();
        /// <summary>
        /// 获取对象中的公有属性
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性名称</param>
        /// <returns>属性信息</returns>
        /// <exception cref="Exception">属性未找到异常</exception>
        public static PropertyInfo GetPropertyInfo(object obj, string propertyName)
        {
            PropertyInfo? pi = null;
            string key = obj.GetType().FullName + "." + propertyName;
            lock (_reflectLock)
            {
                if (_propertyCache.ContainsKey(key))
                {
                    pi = _propertyCache[key];
                }
                else
                {
                    pi = obj.GetType().GetProperty(propertyName);
                    if (pi == null)
                    {
                        throw new Exception(string.Format("属性：{0}不存在", propertyName));
                    }
                    _propertyCache.Add(key, pi);
                }
            }
            return pi;
        }

        /// <summary>
        /// 获取所有对象的公共属性
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns>属性集合</returns>
        public static List<PropertyInfo> GetProperties(object obj)
        {
            return GetProperties(obj.GetType());
        }

        /// <summary>
        /// 获取所有对象的公共属性
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <returns>属性集合</returns>
        public static List<PropertyInfo> GetProperties<T>() where T : class
        {
            return GetProperties(typeof(T));
        }

        /// <summary>
        /// 获取所有对象的公共属性
        /// </summary>
        /// <param name="type">对象的类型</param>
        /// <returns>属性集合</returns>
        /// <exception cref="Exception">反射过程遇到的异常</exception>
        public static List<PropertyInfo> GetProperties(Type type)
        {
            string? key = type.FullName;
            if (key == null || string.IsNullOrEmpty(key.Trim()))
            {
                throw new Exception("要查找的对象没有名称");
            }
            List<PropertyInfo> list = new List<PropertyInfo>();
            lock (_reflectPropertiesLock)
            {
                if (_propertiesCache.ContainsKey(key))
                {
                    list = _propertiesCache[key];
                }
                else
                {
                    PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                    if (propertyInfos != null)
                    {
                        list.AddRange(propertyInfos);
                    }
                    else
                    {
                        throw new Exception("没有找到公共属性");
                    }
                    _propertiesCache.Add(key, list);
                }
            }
            return list;
        }
    }
}
